"""
战斗队列管理器
用于管理世界杯比赛的分批次战斗处理
"""
import logging
import threading
import time
from typing import List, Optional
from django.utils import timezone
from django.db import transaction
from django.conf import settings
from .models import Battle, WorldCup
from .node_server_manager import get_node_server_manager

logger = logging.getLogger(__name__)


class BattleQueueManager:
    """战斗队列管理器"""

    def __init__(self, max_concurrent_battles: int = None):
        """
        初始化战斗队列管理器

        Args:
            max_concurrent_battles: 最大并发战斗数量，如果为None则使用settings配置
        """
        if max_concurrent_battles is None:
            max_concurrent_battles = settings.BATTLE_QUEUE_MANAGER.get('MAX_CONCURRENT_BATTLES', 4)
        self.max_concurrent_battles = max_concurrent_battles
        self.running_battles = set()  # 当前运行中的战斗ID集合
        self.pending_battles = []     # 待处理的战斗队列
        self.is_processing = False    # 是否正在处理队列
        self.lock = threading.Lock()  # 线程锁
        self.stop_event = threading.Event()  # 停止事件
        self.processor_thread = None  # 处理线程

    def start_processing(self):
        """启动队列处理"""
        with self.lock:
            if self.is_processing:
                logger.warning("战斗队列处理器已在运行中")
                return

            self.is_processing = True
            self.stop_event.clear()
            self.processor_thread = threading.Thread(target=self._process_queue, daemon=True)
            self.processor_thread.start()
            logger.info("战斗队列处理器已启动")

    def stop_processing(self):
        """停止队列处理"""
        with self.lock:
            if not self.is_processing:
                return

            self.is_processing = False
            self.stop_event.set()

        if self.processor_thread and self.processor_thread.is_alive():
            timeout = settings.BATTLE_QUEUE_MANAGER.get('PROCESSOR_THREAD_JOIN_TIMEOUT', 5)
            self.processor_thread.join(timeout=timeout)

        logger.info("战斗队列处理器已停止")

    def add_battles_to_queue(self, battle_ids: List[int]):
        """
        将战斗添加到队列

        Args:
            battle_ids: 战斗ID列表
        """
        with self.lock:
            self.pending_battles.extend(battle_ids)
            logger.info(f"已添加 {len(battle_ids)} 场战斗到队列，当前队列长度: {len(self.pending_battles)}")

    def get_queue_status(self) -> dict:
        """获取队列状态"""
        with self.lock:
            return {
                'is_processing': self.is_processing,
                'running_battles': len(self.running_battles),
                'pending_battles': len(self.pending_battles),
                'max_concurrent': self.max_concurrent_battles,
                'available_slots': self.max_concurrent_battles - len(self.running_battles)
            }

    def _process_queue(self):
        """队列处理主循环"""
        logger.info("开始处理战斗队列")

        while self.is_processing and not self.stop_event.is_set():
            try:
                # 清理已完成的战斗
                self._cleanup_finished_battles()

                # 启动新的战斗
                self._start_pending_battles()

                # 等待一段时间再检查
                queue_check_interval = settings.BATTLE_QUEUE_MANAGER.get('QUEUE_CHECK_INTERVAL', 5)
                self.stop_event.wait(timeout=queue_check_interval)

            except Exception as e:
                logger.error(f"队列处理出错: {e}")
                error_retry_interval = settings.BATTLE_QUEUE_MANAGER.get('ERROR_RETRY_INTERVAL', 5)
                time.sleep(error_retry_interval)

        logger.info("战斗队列处理结束")

    def _cleanup_finished_battles(self):
        """清理已完成的战斗"""
        if not self.running_battles:
            return

        # 查询已完成的战斗
        finished_battle_ids = set(
            Battle.objects.filter(
                id__in=self.running_battles,
                status__in=['finished', 'error']
            ).values_list('id', flat=True)
        )

        if finished_battle_ids:
            with self.lock:
                self.running_battles -= finished_battle_ids
                logger.info(f"清理了 {len(finished_battle_ids)} 场已完成的战斗")

    def _start_pending_battles(self):
        """启动待处理的战斗"""
        with self.lock:
            available_slots = self.max_concurrent_battles - len(self.running_battles)

            if available_slots <= 0 or not self.pending_battles:
                return

            # 取出可以启动的战斗数量
            battles_to_start = self.pending_battles[:available_slots]
            self.pending_battles = self.pending_battles[available_slots:]

        # 启动战斗（为世界杯战斗添加间隔）
        for i, battle_id in enumerate(battles_to_start):
            try:
                # 为世界杯战斗添加间隔，防止并发问题
                if i > 0:  # 第一个战斗不需要等待
                    battle = Battle.objects.filter(id=battle_id).first()
                    if battle and battle.battle_type in ['worldcup_regular', 'worldcup_championship']:
                        interval = settings.BATTLE_QUEUE_MANAGER.get('WORLDCUP_BATTLE_INTERVAL', 5)
                        logger.info(f"世界杯战斗 {battle_id} 等待{interval}秒后启动...")
                        time.sleep(interval)

                if self._start_single_battle(battle_id):
                    with self.lock:
                        self.running_battles.add(battle_id)
                    logger.info(f"成功启动战斗 {battle_id}")
                else:
                    logger.error(f"启动战斗 {battle_id} 失败")

            except Exception as e:
                logger.error(f"启动战斗 {battle_id} 时出错: {e}")

    def _start_single_battle(self, battle_id: int) -> bool:
        """
        启动单个战斗

        Args:
            battle_id: 战斗ID

        Returns:
            bool: 是否启动成功
        """
        try:
            battle = Battle.objects.get(id=battle_id)

            # 检查战斗状态
            if battle.status != 'pending':
                logger.warning(f"战斗 {battle_id} 状态不是pending，跳过启动")
                return False

            # 启动战斗
            from .views import start_battle
            start_battle(battle)
            return True

        except Battle.DoesNotExist:
            logger.error(f"战斗 {battle_id} 不存在")
            return False
        except Exception as e:
            logger.error(f"启动战斗 {battle_id} 时出错: {e}")
            return False


# 全局战斗队列管理器实例
_battle_queue_manager = None
_manager_lock = threading.Lock()


def get_battle_queue_manager() -> BattleQueueManager:
    """获取全局战斗队列管理器实例"""
    global _battle_queue_manager

    if _battle_queue_manager is None:
        with _manager_lock:
            if _battle_queue_manager is None:
                _battle_queue_manager = BattleQueueManager()

    return _battle_queue_manager


def start_worldcup_regular_season_battles(worldcup_id: int) -> dict:
    """
    启动世界杯常规赛战斗

    Args:
        worldcup_id: 世界杯ID

    Returns:
        dict: 处理结果
    """
    try:
        worldcup = WorldCup.objects.get(id=worldcup_id)

        # 获取所有待启动的常规赛战斗
        pending_battles = Battle.objects.filter(
            battle_type='worldcup_regular',
            status='pending'
        ).filter(
            worldcupmatch__worldcup=worldcup
        ).values_list('id', flat=True)

        pending_battle_ids = list(pending_battles)

        if not pending_battle_ids:
            return {
                'success': True,
                'message': '没有待启动的战斗',
                'total_battles': 0
            }

        # 获取队列管理器并启动处理
        queue_manager = get_battle_queue_manager()
        queue_manager.start_processing()

        # 将战斗添加到队列
        queue_manager.add_battles_to_queue(pending_battle_ids)

        return {
            'success': True,
            'message': f'已将 {len(pending_battle_ids)} 场战斗添加到队列',
            'total_battles': len(pending_battle_ids),
            'queue_status': queue_manager.get_queue_status()
        }

    except WorldCup.DoesNotExist:
        return {
            'success': False,
            'error': f'世界杯 {worldcup_id} 不存在'
        }
    except Exception as e:
        logger.error(f"启动世界杯常规赛战斗失败: {e}")
        return {
            'success': False,
            'error': str(e)
        }


def start_worldcup_championship_battles(worldcup_id: int, stage: str = 'round_16') -> dict:
    """
    启动世界杯冠军赛战斗

    Args:
        worldcup_id: 世界杯ID
        stage: 冠军赛阶段

    Returns:
        dict: 处理结果
    """
    try:
        worldcup = WorldCup.objects.get(id=worldcup_id)

        # 获取所有待启动的冠军赛战斗
        pending_battles = Battle.objects.filter(
            battle_type='worldcup_championship',
            status='pending'
        ).filter(
            worldcupmatch__worldcup=worldcup,
            worldcupmatch__stage=stage
        ).values_list('id', flat=True)

        pending_battle_ids = list(pending_battles)

        if not pending_battle_ids:
            return {
                'success': True,
                'message': '没有待启动的战斗',
                'total_battles': 0
            }

        # 获取队列管理器并启动处理
        queue_manager = get_battle_queue_manager()
        queue_manager.start_processing()

        # 将战斗添加到队列
        queue_manager.add_battles_to_queue(pending_battle_ids)

        return {
            'success': True,
            'message': f'已将 {len(pending_battle_ids)} 场{stage}战斗添加到队列',
            'total_battles': len(pending_battle_ids),
            'queue_status': queue_manager.get_queue_status()
        }

    except WorldCup.DoesNotExist:
        return {
            'success': False,
            'error': f'世界杯 {worldcup_id} 不存在'
        }
    except Exception as e:
        logger.error(f"启动世界杯冠军赛战斗失败: {e}")
        return {
            'success': False,
            'error': str(e)
        }


def get_worldcup_battle_queue_status(worldcup_id: int) -> dict:
    """
    获取世界杯常规赛战斗队列状态

    Args:
        worldcup_id: 世界杯ID

    Returns:
        dict: 队列状态信息
    """
    try:
        worldcup = WorldCup.objects.get(id=worldcup_id)

        # 统计各状态的战斗数量
        battle_stats = {
            'pending': 0,
            'running': 0,
            'finished': 0,
            'error': 0
        }

        battles = Battle.objects.filter(
            battle_type='worldcup_regular',
            worldcupmatch__worldcup=worldcup
        )

        # 使用values和annotate进行高效统计
        from django.db.models import Count
        status_counts = battles.values('status').annotate(count=Count('status'))

        for item in status_counts:
            status = item['status']
            count = item['count']
            if status in battle_stats:
                battle_stats[status] = count

        # 获取队列管理器状态
        queue_manager = get_battle_queue_manager()
        queue_status = queue_manager.get_queue_status()

        return {
            'success': True,
            'worldcup_name': worldcup.name,
            'battle_stats': battle_stats,
            'queue_status': queue_status,
            'total_battles': sum(battle_stats.values())
        }

    except WorldCup.DoesNotExist:
        return {
            'success': False,
            'error': f'世界杯 {worldcup_id} 不存在'
        }
    except Exception as e:
        logger.error(f"获取队列状态失败: {e}")
        return {
            'success': False,
            'error': str(e)
        }


def get_worldcup_championship_queue_status(worldcup_id: int) -> dict:
    """
    获取世界杯冠军赛队列状态

    Args:
        worldcup_id: 世界杯ID

    Returns:
        dict: 冠军赛队列状态信息
    """
    try:
        worldcup = WorldCup.objects.get(id=worldcup_id)

        # 统计各状态的冠军赛战斗数量
        battle_stats = {
            'pending': 0,
            'running': 0,
            'finished': 0,
            'error': 0
        }

        battles = Battle.objects.filter(
            battle_type='worldcup_championship',
            worldcupmatch__worldcup=worldcup
        )

        # 使用values和annotate进行高效统计
        from django.db.models import Count
        status_counts = battles.values('status').annotate(count=Count('status'))

        for item in status_counts:
            status = item['status']
            count = item['count']
            if status in battle_stats:
                battle_stats[status] = count

        # 获取队列管理器状态
        queue_manager = get_battle_queue_manager()
        queue_status = queue_manager.get_queue_status()

        return {
            'success': True,
            'worldcup_name': worldcup.name,
            'battle_stats': battle_stats,
            'queue_status': queue_status,
            'total_battles': sum(battle_stats.values())
        }

    except WorldCup.DoesNotExist:
        return {
            'success': False,
            'error': f'世界杯 {worldcup_id} 不存在'
        }
    except Exception as e:
        logger.error(f"获取冠军赛队列状态失败: {e}")
        return {
            'success': False,
            'error': str(e)
        }


def restart_worldcup_championship_queue(worldcup_id: int) -> dict:
    """
    重启世界杯冠军赛队列（处理所有冠军赛阶段的待处理战斗）

    Args:
        worldcup_id: 世界杯ID

    Returns:
        dict: 处理结果
    """
    try:
        worldcup = WorldCup.objects.get(id=worldcup_id)

        # 获取所有待启动的冠军赛战斗（所有阶段）
        pending_battles = Battle.objects.filter(
            battle_type='worldcup_championship',
            status='pending'
        ).filter(
            worldcupmatch__worldcup=worldcup
        ).values_list('id', flat=True)

        pending_battle_ids = list(pending_battles)

        # 获取队列管理器并启动处理
        queue_manager = get_battle_queue_manager()
        queue_manager.start_processing()

        if pending_battle_ids:
            # 将战斗添加到队列
            queue_manager.add_battles_to_queue(pending_battle_ids)
            message = f'冠军赛队列已重启，已将 {len(pending_battle_ids)} 场待处理战斗添加到队列'
        else:
            message = '冠军赛队列已重启，当前没有待处理的战斗'

        return {
            'success': True,
            'message': message,
            'total_battles': len(pending_battle_ids),
            'queue_status': queue_manager.get_queue_status()
        }

    except WorldCup.DoesNotExist:
        return {
            'success': False,
            'error': f'世界杯 {worldcup_id} 不存在'
        }
    except Exception as e:
        logger.error(f"重启世界杯冠军赛队列失败: {e}")
        return {
            'success': False,
            'error': str(e)
        }


class ManualBattleQueueManager:
    """手动对战队列管理器 - 管理练习赛和排位赛"""

    def __init__(self):
        """初始化手动对战队列管理器"""
        battle_config = getattr(settings, 'BATTLE_QUEUE_MANAGER', {})
        self.max_queue_size = battle_config.get('MANUAL_BATTLE_QUEUE_SIZE', 10)  # 队列最大容量
        self.max_concurrent_battles = battle_config.get('MANUAL_BATTLE_MAX_CONCURRENT', 3)  # 最大并发对战数
        self.battle_start_interval = battle_config.get('MANUAL_BATTLE_START_INTERVAL', 5)  # 启动对战间隔（秒）
        self.is_processing = False
        self.lock = threading.Lock()
        self.stop_event = threading.Event()
        self.processor_thread = None
        logger.info("手动对战队列管理器已初始化")

    def start_processing(self):
        """启动队列处理"""
        with self.lock:
            if self.is_processing:
                logger.warning("手动对战队列处理器已在运行中")
                return

            self.is_processing = True
            self.stop_event.clear()

            # 重新加载等待中的对战到队列
            self._reload_waiting_battles()

            self.processor_thread = threading.Thread(target=self._process_queue, daemon=True)
            self.processor_thread.start()
            logger.info("手动对战队列处理器已启动")

    def stop_processing(self):
        """停止队列处理"""
        with self.lock:
            if not self.is_processing:
                return

            self.is_processing = False
            self.stop_event.set()

        if self.processor_thread and self.processor_thread.is_alive():
            self.processor_thread.join(timeout=5)

        logger.info("手动对战队列处理器已停止")

    def add_battle_to_queue(self, battle_id: int) -> dict:
        """
        将对战添加到队列

        Args:
            battle_id: 对战ID

        Returns:
            dict: 操作结果
        """
        try:
            from .models import Battle

            battle = Battle.objects.get(id=battle_id)

            # 检查对战类型是否支持
            if battle.battle_type not in ['practice', 'ranked']:
                return {
                    'success': False,
                    'error': f'不支持的对战类型: {battle.battle_type}'
                }

            # 检查队列容量
            queue_count = self._get_queue_count()
            if queue_count >= self.max_queue_size:
                return {
                    'success': False,
                    'error': f'队列已满，当前队列数量: {queue_count}/{self.max_queue_size}'
                }

            # 确保对战状态为pending（等待开始）
            if battle.status != 'pending':
                battle.status = 'pending'
                battle.save(update_fields=['status'])

            logger.info(f"对战 {battle_id} 已添加到队列")
            return {
                'success': True,
                'message': '对战已添加到队列',
                'queue_position': queue_count + 1
            }

        except Battle.DoesNotExist:
            return {
                'success': False,
                'error': '对战不存在'
            }
        except Exception as e:
            logger.error(f"添加对战到队列失败: {e}")
            return {
                'success': False,
                'error': str(e)
            }

    def get_queue_status(self) -> dict:
        """获取队列状态"""
        try:
            from .models import Battle

            # 获取队列中的对战数量
            queue_count = self._get_queue_count()

            # 获取正在进行的对战数量
            running_count = Battle.objects.filter(
                battle_type__in=['practice', 'ranked'],
                status='running'
            ).count()

            # 获取各类型对战的详细信息
            practice_queue = Battle.objects.filter(
                battle_type='practice',
                status='pending'
            ).count()

            ranked_queue = Battle.objects.filter(
                battle_type='ranked',
                status='pending'
            ).count()

            practice_running = Battle.objects.filter(
                battle_type='practice',
                status='running'
            ).count()

            ranked_running = Battle.objects.filter(
                battle_type='ranked',
                status='running'
            ).count()

            return {
                'is_processing': self.is_processing,
                'queue_count': queue_count,
                'max_queue_size': self.max_queue_size,
                'running_count': running_count,
                'max_concurrent_battles': self.max_concurrent_battles,
                'available_slots': self.max_concurrent_battles - running_count,
                'practice_queue': practice_queue,
                'ranked_queue': ranked_queue,
                'practice_running': practice_running,
                'ranked_running': ranked_running,
                'can_add_to_queue': queue_count < self.max_queue_size
            }

        except Exception as e:
            logger.error(f"获取队列状态失败: {e}")
            return {
                'error': str(e)
            }

    def _get_queue_count(self) -> int:
        """获取队列中的对战数量"""
        from .models import Battle
        return Battle.objects.filter(
            battle_type__in=['practice', 'ranked'],
            status='pending'
        ).count()

    def _get_running_count(self) -> int:
        """获取运行中的对战数量"""
        from .models import Battle
        return Battle.objects.filter(
            battle_type__in=['practice', 'ranked'],
            status='running'
        ).count()

    def _reload_waiting_battles(self):
        """重新加载等待中的对战到队列"""
        try:
            from .models import Battle

            # 查找所有等待中的练习赛和排位赛
            waiting_battles = Battle.objects.filter(
                battle_type__in=['practice', 'ranked'],
                status='pending'
            ).order_by('created_at')

            # 确保状态为pending
            for battle in waiting_battles:
                if battle.status != 'pending':
                    battle.status = 'pending'
                    battle.save(update_fields=['status'])

            logger.info(f"重新加载了 {waiting_battles.count()} 个等待中的对战到队列")

        except Exception as e:
            logger.error(f"重新加载等待对战失败: {e}")

    def _process_queue(self):
        """队列处理主循环"""
        logger.info("开始处理手动对战队列")

        while self.is_processing and not self.stop_event.is_set():
            try:
                # 检查并启动新的对战
                self._start_pending_battles()

                # 等待指定间隔
                if self.stop_event.wait(self.battle_start_interval):
                    break

            except Exception as e:
                logger.error(f"处理队列时发生错误: {e}")
                if self.stop_event.wait(self.battle_start_interval):
                    break

        logger.info("手动对战队列处理已停止")

    def _start_pending_battles(self):
        """启动等待中的对战"""
        try:
            from .models import Battle

            # 获取当前正在运行的对战数量
            running_count = Battle.objects.filter(
                battle_type__in=['practice', 'ranked'],
                status='running'
            ).count()

            # 计算可以启动的对战数量
            available_slots = self.max_concurrent_battles - running_count

            if available_slots <= 0:
                return

            # 获取等待中的对战，按创建时间排序
            waiting_battles = Battle.objects.filter(
                battle_type__in=['practice', 'ranked'],
                status='pending'
            ).order_by('created_at')[:available_slots]

            for battle in waiting_battles:
                try:
                    # 启动对战
                    success = self._start_single_battle(battle.id)

                    if success:
                        logger.info(f"成功启动对战 {battle.id}")
                    else:
                        logger.warning(f"启动对战 {battle.id} 失败")

                except Exception as e:
                    logger.error(f"处理对战 {battle.id} 时发生错误: {e}")
                    # 重置为等待状态
                    battle.queue_status = 'waiting'
                    battle.save(update_fields=['queue_status'])

        except Exception as e:
            logger.error(f"启动等待对战时发生错误: {e}")

    def _start_single_battle(self, battle_id: int) -> bool:
        """
        启动单个对战

        Args:
            battle_id: 对战ID

        Returns:
            bool: 是否启动成功
        """
        try:
            from django.db import transaction
            from .battle_engine import get_battle_engine_manager
            from .models import Battle

            # 使用数据库事务确保原子性操作
            with transaction.atomic():
                try:
                    # 使用 select_for_update 锁定战斗记录，防止并发修改
                    battle = Battle.objects.select_for_update().get(id=battle_id)

                    # 检查战斗状态，只有 pending 状态的战斗才能启动
                    if battle.status != 'pending':
                        logger.warning(f"战斗 {battle_id} 状态不是pending ({battle.status})，跳过启动")
                        return False

                    # 立即更新状态为 running，防止其他进程重复启动
                    battle.status = 'running'
                    battle.started_at = timezone.now()
                    battle.save(update_fields=['status', 'started_at'])

                    logger.info(f"战斗 {battle_id} 状态已更新为running")

                except Battle.DoesNotExist:
                    logger.error(f"战斗 {battle_id} 不存在")
                    return False

            # 在事务外启动战斗引擎（避免长时间持有锁）
            manager = get_battle_engine_manager()
            result = manager.start_battle(str(battle_id))
            return result

        except Exception as e:
            logger.error(f"启动对战 {battle_id} 失败: {e}")
            return False


# 全局手动对战队列管理器实例
_manual_battle_queue_manager = None
_manual_manager_lock = threading.Lock()


def get_manual_battle_queue_manager() -> ManualBattleQueueManager:
    """获取手动对战队列管理器实例（单例模式）"""
    global _manual_battle_queue_manager

    if _manual_battle_queue_manager is None:
        with _manual_manager_lock:
            if _manual_battle_queue_manager is None:
                _manual_battle_queue_manager = ManualBattleQueueManager()

    return _manual_battle_queue_manager